feat: add limits to input attributes#4063
Conversation
Will not compile due to std::optional instantiation (used by m_minValue and m_maxVavlue) for abstract types like PartitionBase
setLimits() has the same capabilities and should be the only one kept.
dkachuma
left a comment
There was a problem hiding this comment.
I really like this idea. It will simplify greatly some of the boiler plate validation code.
Will this work for lists of numbers?
This part may be refactored, to build the range string somewhere else
MelReyCG
left a comment
There was a problem hiding this comment.
Please apply this feature on at least one (maybe basic) 'Group' to demonstrate usage (array and scalar ideally).
| * // default to true. | ||
| * @endcode | ||
| */ | ||
| Bound( T v, bool inclusive = true ) |
There was a problem hiding this comment.
do we want this constructor explicit?
There was a problem hiding this comment.
It was made not explicit so we can write .setLimits( 0.0, 1.0 ) instead of .setLimits( WrapperBound{ 0.0 }, WrapperBound{ 1.0 } )
There was a problem hiding this comment.
That implicit conversion from any double to your type, at this (critical) level of the inclusion hierarchy, may cause the compiler to try undesired casts.
Why not an overload or a different signature for setLimits()?
Applied to |
| string const msg = GEOS_FMT( "Value {} for attribute '{}' is outside the allowed range {}.", | ||
| value, getDataContext(), m_limits.getRangeStr() ); | ||
|
|
||
| switch( m_limitsMode ) | ||
| { | ||
| case WrapperLimitsMode::Warning: | ||
| GEOS_WARNING( msg ); | ||
| break; | ||
|
|
||
| case WrapperLimitsMode::Error: | ||
| GEOS_THROW( msg, InputError ); | ||
| break; | ||
|
|
||
| default: | ||
| GEOS_LOG_RANK_0( "Unimplemented WrapperLimitsMode" ); | ||
| break; |
There was a problem hiding this comment.
What gives the following in the log?
| string const msg = GEOS_FMT( "Value {} for attribute '{}' is outside the allowed range {}.", | |
| value, getDataContext(), m_limits.getRangeStr() ); | |
| switch( m_limitsMode ) | |
| { | |
| case WrapperLimitsMode::Warning: | |
| GEOS_WARNING( msg ); | |
| break; | |
| case WrapperLimitsMode::Error: | |
| GEOS_THROW( msg, InputError ); | |
| break; | |
| default: | |
| GEOS_LOG_RANK_0( "Unimplemented WrapperLimitsMode" ); | |
| break; | |
| string const msg = GEOS_FMT( "Value {} is outside the allowed range {}.", | |
| value, m_limits.getRangeStr() ); | |
| switch( m_limitsMode ) | |
| { | |
| case WrapperLimitsMode::Warning: | |
| GEOS_WARNING( msg, getDataContext() ); | |
| break; | |
| case WrapperLimitsMode::Error: | |
| GEOS_THROW( msg, InputError, getDataContext() ); | |
| break; | |
| default: | |
| GEOS_LOG_RANK_0( "Unimplemented WrapperLimitsMode" ); | |
| break; |
There was a problem hiding this comment.
can you give a stdout sample of the message?
There was a problem hiding this comment.
I updated the description
| * // default to true. | ||
| * @endcode | ||
| */ | ||
| Bound( T v, bool inclusive = true ) |
There was a problem hiding this comment.
That implicit conversion from any double to your type, at this (critical) level of the inclusion hierarchy, may cause the compiler to try undesired casts.
Why not an overload or a different signature for setLimits()?
Causes problems with getDataContext(). See src/coreComponents/dataRepository/Group.cpp:139 "In the Conduit node hierarchy everything begins with 'Problem', we should change it so that the ProblemManager actually uses the root Conduit Node but that will require a full rebaseline."
| string const limitsString = wrapper.getLimitsString(); | ||
| if( !limitsString.empty() ) | ||
| { | ||
| commentString += GEOS_FMT( " Allowed range: {}", limitsString ); | ||
| } |
There was a problem hiding this comment.
Maybe add a line break for visibility.
| string const limitsString = wrapper.getLimitsString(); | |
| if( !limitsString.empty() ) | |
| { | |
| commentString += GEOS_FMT( " Allowed range: {}", limitsString ); | |
| } | |
| string const limitsString = wrapper.getLimitsString(); | |
| if( !limitsString.empty() ) | |
| commentString += GEOS_FMT( "\nAllowed range: {}", limitsString ); |
As it is proposed, the appended string can appear in another sentence:
<!--waterOilRelPermExponent => Rel perm power law exponent for the pair (water phase, oil phase) at residual gas saturation
The expected format is "{ waterExp, oilExp }", in that order Allowed range: [0, +inf)-->
| template< typename T > | ||
| WrapperBound< T > inclusive( T value ) | ||
| { | ||
| return WrapperBound< T >{ value, /*isInclusive*/ true }; | ||
| } |
There was a problem hiding this comment.
I'm afraid those free functions are too global seen their names and scope. A simple solution would be to scope that in a namespace or in the WrapperBound class as static function.
| getMinValue() const | ||
| { | ||
| return m_limits.min; | ||
| } |
There was a problem hiding this comment.
Is it reading the values or the bound?
In case of reading bound, it can be misleading, I suggest:
| getMinValue() const | |
| { | |
| return m_limits.min; | |
| } | |
| getMinBound() const | |
| { | |
| return m_limits.min; | |
| } |
This PR adds the possibility to specify a min and/or a max value to
Wrappers attributes.The goal is to provide the foundations for two follow-up efforts planned in future PRs:
Usage:
This will serve as a documentation for values, but also prevents users from making typos that could lead to wrong results, taking time to find (if noticed).
The limits come with 3 modes:
The mode can be set when specifying the limit, using this syntax:
... or it will default to
Errorif unset.Limits also support inclusive and exclusive bounds:
Not using
inclusive(...)orexclusive(...)will default to an inclusive limit.When using
LimitMode::Error, the following output is produced when an input value exceeds a limit:Some examples: